module IsTree
  module ActiveRecord
    module Tree
    
      def self.included(base)
        base.extend(ClassMethods)
      end
    
      module ClassMethods
        
        def is_tree(options = {})
          configuration = { :foreign_key => "parent_id", :order => nil, :counter_cache => nil}
          configuration.merge!(options) if options.is_a?(Hash)
          
          has_many_params = {:order => configuration[:order]}.merge(configuration[:dependent] ? {:dependent => configuration[:dependent]} : {})
          association_params = {:class_name => self.name, :foreign_key => configuration[:foreign_key]}
          root_scope_params = {:conditions => {configuration[:foreign_key] => nil}, :order => configuration[:order]}
          
          belongs_to :parent, association_params.merge({:counter_cache => configuration[:counter_cache]})
          has_many :children, association_params.merge(has_many_params)
          
          named_scope :roots, root_scope_params
          named_scope :with_parent, {:include => :parent}
          named_scope :with_children, {:include => :children}
          
          self.class_eval do            
            include IsTree::ActiveRecord::Tree::InstanceMethods
            
            def self.root
              self.roots.first
            end
          end
          
        end
        
      end
      
      module InstanceMethods
        
        def ancestors
          node, nodes = self, []
          nodes << node = node.parent while node.parent
          nodes
        end

        def root
          self.ancestors.last
        end
        
        def leaf?
          self.children.empty?
        end
        
        def root?
          self.parent.nil?
        end
        
        def siblings
          self.self_and_siblings.scoped(:conditions => ["id <> :id",{:id => self.id}])
        end
        
        def self_and_siblings
          self.parent_id ? self.class.scoped_by_parent_id(self.parent_id) : self.class.roots
        end
        
      end
    
    end
  end
end